#include "UnrealBrush.h"
#include <QMessageBox>
#include <QFileDialog>
#include "ResizeDirectMappingDialog.h"
#include "ResizeReverseMappingDialog.h"
#include "FilterSizeDialog.h"

UnrealBrush::UnrealBrush(QWidget *parent, Qt::WFlags flags)
    : QMainWindow(parent, flags)
{
    ui.setupUi(this);
    model = new Model;
    model->Register(this);

	ui.imageScrollArea->setWidget(ui.imageLabel);

    connect(ui.actionOpen, SIGNAL(triggered()), this, SLOT(open()));
    connect(ui.actionInverse, SIGNAL(triggered()), this, SLOT(inverse()));
    connect(ui.actionGrayscale, SIGNAL(triggered()), this, SLOT(grayscale()));
    connect(ui.actionResizeDirectMapping, SIGNAL(triggered()), this, SLOT(resizeDirectMapping()));
    connect(ui.actionResizeReverseMapping, SIGNAL(triggered()), this, SLOT(resizeReverseMapping()));
    connect(ui.actionFlipHorizontally, SIGNAL(triggered()), this, SLOT(flipHorizontally()));
    connect(ui.actionFlipVertically, SIGNAL(triggered()), this, SLOT(flipVertically()));
    connect(ui.actionBlurWeighted, SIGNAL(triggered()), this, SLOT(blurWeighted()));
    connect(ui.actionBlurMean, SIGNAL(triggered()), this, SLOT(blurMean()));
    connect(ui.actionSharpenPoint, SIGNAL(triggered()), this, SLOT(sharpenPoint()));
    connect(ui.actionHorizontalLineSharpening, SIGNAL(triggered()), this, SLOT(sharpenHorizontalLine()));
    connect(ui.actionVerticalLineSharpening, SIGNAL(triggered()), this, SLOT(sharpenVerticalLine()));
    connect(ui.actionRightDiagonalLineSharpening, SIGNAL(triggered()), this, SLOT(sharpenRightDiagonalLine()));
    connect(ui.actionLeftDiagonalLineSharpening, SIGNAL(triggered()), this, SLOT(sharpenLeftDiagonalLine()));
    connect(ui.actionPointDetection, SIGNAL(triggered()), this, SLOT(detectPoint()));
    connect(ui.actionHorizontalLineDetection, SIGNAL(triggered()), this, SLOT(detectHorizontalLine()));
    connect(ui.actionVerticalLineDetection, SIGNAL(triggered()), this, SLOT(detectVerticalLine()));
    connect(ui.actionRightDiagonalLineDetection, SIGNAL(triggered()), this, SLOT(detectRightDiagonalLine()));
    connect(ui.actionLeftDiagonalLineDetection, SIGNAL(triggered()), this, SLOT(detectLeftDiagonalLine()));
	connect(ui.actionBasic_Global, SIGNAL(triggered()), this, SLOT(basicGlobalThresholding()));
	connect(ui.actionOptimum_Global, SIGNAL(triggered()), this, SLOT(optimumGlobalThresholding()));
	connect(ui.actionAdaptive, SIGNAL(triggered()), this, SLOT(adaptiveThresholding()));
	connect(ui.contrastSlideBar, SIGNAL(valueChanged(int)), this, SLOT(contrastSlideBarChanged(int)));
	connect(ui.brightnessSlideBar, SIGNAL(valueChanged(int)), this, SLOT(brightnessSlideBarChanged(int)));
}

UnrealBrush::~UnrealBrush()
{
    delete model;
}

void UnrealBrush::OnImageUpdated(bool updateHistogram)
{
    QImage image(model->Image()->Width(), model->Image()->Height(), QImage::Format_RGB32);
    int width = model->Image()->Width();
    int height = model->Image()->Height();

	model->Histogram()->Clear();
    for(int h = 0; h < height; h++)
    {
        for(int w = 0; w < width; w++)
        {
            image.setPixel(w, h, qRgba(model->Image()->Pixels()[h][w].R, model->Image()->Pixels()[h][w].G, model->Image()->Pixels()[h][w].B, model->Image()->Pixels()[h][w].A));
			if(updateHistogram)
				model->Histogram()->AddPixel(model->Image()->Pixels()[h][w]);
        }
    }

	ui.imageLabel->setPixmap(QPixmap::fromImage(image));
    ui.imageLabel->adjustSize();
	if(updateHistogram)
		DrawHistogram();
}

void UnrealBrush::DrawHistogram()
{
	model->Histogram()->Normalize(model->Image()->Width() * model->Image()->Height());
	QImage histogramImage(HIST_WIDTH, HIST_HEIGHT, QImage::Format_ARGB32);

	PixelBuffer* buffer = model->Histogram()->RedBuffer();
	for(int i = 0 ; i < HIST_HEIGHT ; i++)
	{
		for(int j = 0 ; j < HIST_WIDTH ; j++)
		{
			histogramImage.setPixel(j, i, qRgb(buffer->Pixels()[i][j].R, buffer->Pixels()[i][j].G, buffer->Pixels()[i][j].B));
		}
	}
	ui.histogramLabel->setPixmap(QPixmap::fromImage(histogramImage));
}

/* Slots */
void UnrealBrush::inverse()
{
    model->Inverse();
}

void UnrealBrush::grayscale()
{
    model->Grayscale();
}

void UnrealBrush::resizeDirectMapping()
{
    ResizeDirectMappingDialog resizeDialog;

    if(resizeDialog.exec() == QDialog::Accepted)
    {
        model->ResizeDirectMapping(resizeDialog.GetFactor(), resizeDialog.GetMode());
    }
}

void UnrealBrush::resizeReverseMapping()
{
    ResizeReverseMappingDialog resizeDialog;

    if (resizeDialog.exec() == QDialog::Accepted)
    {
        model->ResizeReverseMapping(resizeDialog.GetWidth(), resizeDialog.GetHeight(), resizeDialog.GetMode());
    }
}

void UnrealBrush::open()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open Image"), QDir::currentPath());

    if(!fileName.isEmpty())
    {
        if(!model->LoadImage(fileName))
        {
            QMessageBox::information(this, tr("Error"), tr("Cannot load image %1").arg(fileName));
        }
   }
}

void UnrealBrush::flipHorizontally()
{
    model->FlipHorizotally();
}

void UnrealBrush::flipVertically()
{
    model->FlipVertically();
}

void UnrealBrush::blurWeighted()
{
    model->ApplyFilter(Filter_Weighted);
}

void UnrealBrush::blurMean()
{
    int maskSize;
    FilterSizeDialog filterSizeDialog;

    if (filterSizeDialog.exec() == QDialog::Accepted)
    {
        maskSize = filterSizeDialog.FilterSize();
        model->ApplyFilter(Filter_Mean, &maskSize);
    }
}

void UnrealBrush::sharpenPoint()
{
    model->ApplyFilter(Filter_PointSharpening);
}

void UnrealBrush::sharpenHorizontalLine()
{
    model->ApplyFilter(Filter_HorizontalLineSharpening);
}

void UnrealBrush::sharpenVerticalLine()
{
    model->ApplyFilter(Filter_VerticalLineSharpening);
}

void UnrealBrush::sharpenRightDiagonalLine()
{
    model->ApplyFilter(Filter_RightDiagonalLineSharpening);
}

void UnrealBrush::sharpenLeftDiagonalLine()
{
    model->ApplyFilter(Filter_LeftDiagonalLineSharpening);
}

void UnrealBrush::detectPoint()
{
    model->ApplyFilter(Filter_PointDetection);
}

void UnrealBrush::detectHorizontalLine()
{
    model->ApplyFilter(Filter_HorizontalLineDetection);
}

void UnrealBrush::detectVerticalLine()
{
    model->ApplyFilter(Filter_VerticalLineDetection);
}

void UnrealBrush::detectRightDiagonalLine()
{
    model->ApplyFilter(Filter_RightDiagonalLineDetection);
}

void UnrealBrush::detectLeftDiagonalLine()
{
    model->ApplyFilter(Filter_LeftDiagonalLineDetection);
}

void UnrealBrush::basicGlobalThresholding()
{
	int T = model->Segment(BasicGlobal, 0.00000001);
    QMessageBox::information(this, tr("Threshold Value"), tr("Threshold =  %1").arg(T));
}

void UnrealBrush::optimumGlobalThresholding()
{
	int T = model->Segment(OptimumGlobal, -1);
    QMessageBox::information(this, tr("Threshold Value"), tr("Threshold =  %1").arg(T));
}

void UnrealBrush::adaptiveThresholding()
{
	model->Segment(Adaptive, 100);
}

void UnrealBrush::contrastSlideBarChanged(int value)
{
	model->Contrast(value);
}

void UnrealBrush::on_okContrastBtn_clicked()
{
	model->CopyTmpBuffer();
	ui.contrastSlideBar->setValue(0);
}

void UnrealBrush::on_brightnessOkBtn_clicked()
{
	model->CopyTmpBuffer();
	ui.brightnessSlideBar->setValue(0);
}

void UnrealBrush::brightnessSlideBarChanged(int value)
{
	model->Brightness(value);
}